﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Data;
using System.Text;
using System.Windows.Forms;
using System.Threading;

namespace Walson.Form.FlightDevice
{
    public partial class Oscilloscope : UserControl
    {
        public const int INTERVAL = 1000; // 采样时间间隔1000ms
        public const int MAX_CURVE_NUM = 10;    // 示波器显示最大曲线数为10
        private const int SCOPE_WIDTH = 500;    // 示波器宽度
        private const int SCOPE_HEIGHT = 500;   // 示波器高度
        private const int SCOPE_FRAME = 25;     // 示波器边框宽度
        private const int DATA_LENGTH = SCOPE_WIDTH;    // 示波器最大采样点数设为示波器宽度
        private Curve[] curve;
        // private ReaderWriterLock datas_lock; // 单线程不需要读写锁
        private Brush brush;
        private Font font;
        private Pen white_dash_pen;
        private bool hold;
        private Bitmap bitmap;
        public Oscilloscope()
        {
            InitializeComponent();

            Scope_Load();
        }
        // 添加曲线
        public bool CreateCurve(int id, Color color, string unit)
        {
            bool re = false;
            if (id >= 0 && id < MAX_CURVE_NUM)
            {
                // datas_lock.AcquireWriterLock(-1);
                if (this.curve[id] == null)
                {
                    this.curve[id] = new Curve();
                }
                if (this.curve[id].show == false)
                {
                    this.curve[id].Init(true, color, DATA_LENGTH, INTERVAL, unit);
                    re = true;
                }
                // datas_lock.ReleaseWriterLock();
            }
            return re;
        }
        // 删除曲线
        public void RemoveCurve(int id)
        {
            // datas_lock.AcquireWriterLock(-1);
            if (this.curve[id] != null)
            {
                if (this.curve[id].show == true)
                {
                    this.curve[id].show = false;
                }
            }
            // datas_lock.ReleaseWriterLock();
            this.Invalidate();
        }
        // 添加单点数据
        public void AddData(int id, float f)
        {
            if (this.hold == false)
            {
                // datas_lock.AcquireWriterLock(-1);
                if (this.curve[id] != null)
                {
                    if (this.curve[id].show == true)
                    {
                        for (int i = Curve.points - 1; i > 0; i--)
                        {
                            if (this.curve[id].counter == 0)
                            {
                                this.curve[id].data_raw[i].X = 0;
                            }
                            else
                            {
                                this.curve[id].data_raw[i].X = this.curve[id].data_raw[i - 1].X + 1;
                            }
                            this.curve[id].data_raw[i].Y = this.curve[id].data_raw[i - 1].Y;
                        }
                        this.curve[id].data_raw[0].X = 0;
                        this.curve[id].data_raw[0].Y = f;
                        if (this.curve[id].counter < Curve.points)
                        {
                            this.curve[id].counter++;
                        }
                    }
                }
                // datas_lock.ReleaseWriterLock();
                this.Invalidate();
            }
        }
        // 暂停波形
        public bool Hold
        {
            set
            {
                this.hold = value;
            }
        }
        // 设置曲线参数
        private void SetCurveOffsetX(int id, int offset_x) // 暂时禁止X轴偏置设置，其原点在右，向左为正方向
        {
            if (this.curve[id] != null)
            {
                Curve.offset_x = offset_x;
                this.Invalidate();
            }
        }
        public void SetCurveOffsetY(int id, int offset_y)
        {
            if (this.curve[id] != null)
            {
                this.curve[id].offset_y = offset_y;
                this.Invalidate();
            }
        }
        public void SetCurveZoomX(int id, float zoom_x)
        {
            if (this.curve[id] != null)
            {
                if (zoom_x >= 1.0f)     // 限制X轴缩放比例 >=1
                {
                    Curve.zoom_x = zoom_x;
                    this.Invalidate();
                }
            }
        }
        public void SetCurveZoomY(int id, float zoom_y)
        {
            if (this.curve[id] != null)
            {
                this.curve[id].zoom_y = zoom_y;
            }
        }
        // 示波器初始化
        private void Scope_Load()
        {
            // datas_lock = new ReaderWriterLock();
            curve = new Curve[MAX_CURVE_NUM];
            Curve.InitStatic(DATA_LENGTH, INTERVAL, 0, 1.0f);
            brush = new SolidBrush(Color.Yellow);
            font = new Font("SimSun", 10, System.Drawing.FontStyle.Regular);
            white_dash_pen = new Pen(Color.White, 1);
            white_dash_pen.DashStyle = DashStyle.Dot;
            hold = false;
        }
        // size改变时刷新
        private void Scope_Resize(object sender, EventArgs e)
        {
            this.Invalidate();
        }
        // 右键菜单about
        private void aboutToolStripMenuItem_Click(object sender, EventArgs e)
        {
            MessageBox.Show("Scope V1.0\r\n\r\nCopyRight dongzr 2010-2012", "About...");
        }
        // 绘图，双缓冲在Scope属性里设置
        protected override void OnPaint( PaintEventArgs e)
        {
            Graphics g = e.Graphics;
            g.SmoothingMode = SmoothingMode.HighSpeed;
            g.PixelOffsetMode = PixelOffsetMode.HighSpeed;
            g.Clear(Color.DarkGray);
            g.ScaleTransform(-(float)this.Width / (SCOPE_WIDTH + SCOPE_FRAME * 2),
                             -(float)this.Height / (SCOPE_HEIGHT + SCOPE_FRAME * 2)); // 缩放，并使XY轴反向
            g.TranslateTransform(-(SCOPE_WIDTH + SCOPE_FRAME), -(SCOPE_HEIGHT / 2 + SCOPE_FRAME)); // 新的坐标原点，位于波形显示区的右侧中点
            // 示波器显示范围指示
            g.SetClip(new Rectangle(0, SCOPE_HEIGHT / 2 + 5, SCOPE_WIDTH, SCOPE_FRAME - 10));
            g.Clear(Color.Black);
            g.DrawRectangle(Pens.YellowGreen, new Rectangle(0, SCOPE_HEIGHT / 2 + 10, (int)(SCOPE_WIDTH / Curve.zoom_x), SCOPE_FRAME - 20));
            // 绘制零点指示标志
            g.SetClip(new Rectangle(SCOPE_WIDTH + 5, -SCOPE_HEIGHT / 2, SCOPE_FRAME - 10, SCOPE_HEIGHT));
            g.Clear(Color.Black);
            for (int ls = 0; ls < MAX_CURVE_NUM; ls++)
            {
                if (this.curve[ls] != null)
                {
                    if (this.curve[ls].show == true)
                    {
                        g.DrawLine(this.curve[ls].pen, SCOPE_WIDTH + 5, this.curve[ls].offset_y, SCOPE_WIDTH + 15, this.curve[ls].offset_y + 3);
                        g.DrawLine(this.curve[ls].pen, SCOPE_WIDTH + 5, this.curve[ls].offset_y, SCOPE_WIDTH + SCOPE_FRAME - 5, this.curve[ls].offset_y);
                        g.DrawLine(this.curve[ls].pen, SCOPE_WIDTH + 5, this.curve[ls].offset_y, SCOPE_WIDTH + 15, this.curve[ls].offset_y - 3);
                    }
                }
            }
            // 设置作图区域为波形显示区，大小为SCOPE_WIDTH*SCOPE_HEIGHT
            g.SetClip(new Rectangle(0, -SCOPE_HEIGHT / 2, SCOPE_WIDTH, SCOPE_HEIGHT));
            g.Clear(Color.Black);
            // 绘制坐标网格
            for (int step = SCOPE_WIDTH / 50, i = 0; i <= 50; i++)
            {
                if (i % 5 == 0)
                {
                    g.DrawLine(white_dash_pen, i * step, -SCOPE_HEIGHT / 2, i * step, SCOPE_HEIGHT / 2);
                }
                else
                {
                    g.DrawLine(white_dash_pen, i * step, -SCOPE_HEIGHT / 2, i * step, -SCOPE_HEIGHT / 2 + step / 2);
                    // g.DrawLine(white_dash_pen, i * step, -step / 4, i * step, step / 4);
                    g.DrawLine(white_dash_pen, i * step, SCOPE_HEIGHT / 2, i * step, SCOPE_HEIGHT / 2 - step / 2);
                }
            }
            for (int step = SCOPE_HEIGHT / 50, i = -25; i <= 25; i++)
            {
                if (i % 5 == 0)
                {
                    g.DrawLine(white_dash_pen, SCOPE_WIDTH, i * step, 0, i * step);
                }
                else
                {
                    g.DrawLine(white_dash_pen, SCOPE_WIDTH, i * step, SCOPE_WIDTH - step / 2, i * step);
                    // g.DrawLine(white_dash_pen, SCOPE_WIDTH / 2 + step / 4, i * step, SCOPE_WIDTH / 2 - step / 4, i * step);
                    g.DrawLine(white_dash_pen, step / 2, i * step, 0, i * step);
                }
            }
            // 绘制data
            // datas_lock.AcquireWriterLock(-1);
            for (int ls = 0; ls < MAX_CURVE_NUM; ls++)
            {
                if (this.curve[ls] != null)
                {
                    if (this.curve[ls].show == true)
                    {
                        // data变换
                        for (int i = 0; i < Curve.points; i++)
                        {
                            this.curve[ls].data_show[i].X = this.curve[ls].data_raw[i].X * Curve.zoom_x + Curve.offset_x;
                            this.curve[ls].data_show[i].Y = this.curve[ls].data_raw[i].Y * this.curve[ls].zoom_y + this.curve[ls].offset_y;
                        }
                        // 显示
                        g.DrawLines(this.curve[ls].pen, this.curve[ls].data_show);
                    }
                }
            }
            // datas_lock.ReleaseWriterLock();
            // 绘制单位坐标
            g.ScaleTransform(-1, -1);
            g.SetClip(new Rectangle(-SCOPE_WIDTH, SCOPE_HEIGHT / 2 + 5, SCOPE_WIDTH, SCOPE_FRAME - 10));
            g.Clear(Color.Black);
            g.DrawString("10     9      8      7      6      5      4      3      2      1     0", font, brush, -SCOPE_WIDTH, SCOPE_HEIGHT / 2 + 5);
            g.RotateTransform(-90);
            g.SetClip(new Rectangle(-SCOPE_HEIGHT / 2, 5, SCOPE_HEIGHT, SCOPE_FRAME - 10));
            g.Clear(Color.Black);
            g.DrawString("-5     -4     -3     -2     -1      0      1      2      3      4      5", font, brush, -SCOPE_HEIGHT / 2, 5);
        }
        private void saveToolStripMenuItem_Click(object sender, EventArgs e)
        {
            bool isSave = true;
            SaveFileDialog saveImageDialog = new SaveFileDialog();
            saveImageDialog.Title = "Save Scope image";
            saveImageDialog.Filter = @".bmp|*.bmp";
            if (saveImageDialog.ShowDialog() == DialogResult.OK)
            {
                string fileName = saveImageDialog.FileName.ToString();
                if (fileName != "" && fileName != null)
                {
                    System.Drawing.Imaging.ImageFormat imgformat = null;
                    imgformat = System.Drawing.Imaging.ImageFormat.Bmp;
                    if (isSave)
                    {
                        try
                        {
                            bitmap = new Bitmap(this.ClientSize.Width, this.ClientSize.Height);
                            this.DrawToBitmap(bitmap, this.ClientRectangle);
                            bitmap.Save(fileName, imgformat);
                            MessageBox.Show("图片已经成功保存!");
                        }
                        catch
                        {
                            MessageBox.Show("保存失败!");
                        }
                        finally
                        {
                            bitmap.Dispose();
                        }
                    }
                }
            }
        }
    }
    internal class Curve
    {
        public bool show;   // 是否显示
        public PointF[] data_raw;   // 数据原始值
        public PointF[] data_show;   // 数据显示值
        public Pen pen;   // 画笔
        public static int points;   // 采样点数
        public string unit;   // 数据的单位
        public static int interval;   // 采样点的时间间隔，单位ms
        public static int offset_x;   // 横轴偏置
        public int offset_y;   // 纵轴偏置
        public static float zoom_x;   // 横轴缩放比例
        public float zoom_y;   // 纵轴缩放比例
        public int counter;
        public Curve()
        {
            this.show = false;
        }
        public static void InitStatic(int points, int interval, int offset_x, float zoom_x)
        {
            Curve.points = points;
            Curve.interval = interval;
            Curve.offset_x = offset_x;
            Curve.zoom_x = zoom_x;
        }
        public void Init(bool show, Color color, int points, int interval, string unit)
        {
            this.show = show;
            this.unit = unit;
            this.pen = new Pen(color, 1);
            this.data_raw = new PointF[Curve.points];
            this.data_show = new PointF[Curve.points];
            this.offset_y = 0;
            this.zoom_y = 1.0f;
            this.counter = 0;
        }
    }
}